'use strict'
/*
闭包

什么是闭包（Closure）
简单讲，闭包就是指有权访问另一个函数作用域中的变量的函数。

MDN 上面这么说：闭包是一种特殊的对象。

它由两部分构成：函数，以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。

这种官方的概念是比较难理解的，在面试的时候说出来也不是很专业，因为没办法有个具体的逻辑。

理解闭包的关键在于：外部函数调用之后其变量对象本应该被销毁，但闭包的存在使我们仍然可以访问外部函数的变量对象，这就是闭包的重要概念。

闭包的一个运用的例子:

function outer(){
    var a=1;
    return function(){
        return a;//返回变量a的值
    };
}

var b=outer();

console.log(b()); // 1


产生一个闭包
创建闭包最常见方式，就是在一个函数内部创建另一个函数。下面例子中的 closure 就是一个闭包：

function func(){
    var a=1;b=2;
    function closure(){//闭包
        return a+b; //返回a+b的值
    }
    return closure;//返回闭包函数
}



闭包的注意事项
通常，函数的作用域及其所有变量都会在函数执行结束后被销毁。但是，在创建了一个闭包以后，这个函数的作用域就会一直保存到闭包不存在为止。

function makeAdd(x){
    return function(y){
        return x+y;
    };
}

var add5=makeAdd(5);
var add10=makeAdd(10);

console.log(add5(2)); //7
console.log(add10(2)); //12

//释放对闭包的引用
add5=null;
add10=null;


从上述代码可以看到add5 和 add10 都是闭包。它们共享相同的函数定义，但是保存了不同的环境。
在 add5 的环境中，x 为 5。而在 add10 中，x 则为 10。最后通过 null 释放了 add5 和 add10 对闭包的引用。

在javascript中，如果一个对象不再被引用，那么这个对象就会被垃圾回收机制回收；

如果两个对象互相引用，而不再被第3者所引用，那么这两个互相引用的对象也会被回收。

闭包只能取得包含函数中的任何变量的最后一个值:

function arrFunc(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=function(){
            return i;
        };
    }
    return arr;
}

arr数组中包含了10个匿名函数，每个匿名函数都能访问外部函数的变量i，那么i是多少呢？

当arrFunc执行完毕后，其作用域被销毁，但它的变量对象仍保存在内存中，得以被匿名访问，这时i的值为10。

要想保存在循环过程中每一个i的值，需要在匿名函数外部再套用一个匿名函数，在这个匿名函数中定义另一个变量并且立即执行来保存i的值。

function arrFunc(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=function(num){
            return num;
        }(i);
    }
    return arr;
}

这时最内部的匿名函数访问的是num的值，所以数组中10个匿名函数的返回值就是1-10。


运用闭包的关键：
闭包引用外部函数变量对象中的值；

在外部函数的外部调用闭包。

闭包的缺陷：
闭包的缺点就是常驻内存会增大内存使用量，并且使用不当很容易造成内存泄露。

如果不是因为某些特殊任务而需要闭包，在没有必要的情况下，在其它函数中创建函数是不明智的，因为闭包对脚本性能具有负面影响，包括处理速度和内存消耗。

练习和测试：

function fun(n,o){
    console.log(o);
    return {
        fun:function(m){
            return fun(m,n);
        }
    };
}

var a=fun(0); //?
a.fun(1);//?
a.fun(2);//?
a.fun(3);//?

var b=fun(0).fun(1).fun(2).fun(3);//?链式函数

var c=fun(0).fun(1);//?
c.fun(1);//?
c.fun(2);//?
*/


function arrFunc(){
    var arr=[];
    for(var i=0;i<10;i++){
        arr[i]=function(num){
            return num;
        }(i);
    }
    return arr;
}

var arr=arrFunc();
console.log(arr[0]);
console.log(arr[1]());
console.log(arr[9]());

// function fun(n,o){
//     console.log(o);
//     return {
//         fun:function(m){
//             return fun(m,n);
//         }
//     };
// }

// var a=fun(0); //?
// console.log(a.fun(1));//?
// console.log(a.fun(2));//?
// console.log(a.fun(3));//?

// var b=fun(0).fun(1).fun(2).fun(3);//?
// console.log(b);
// var c=fun(0).fun(1);//?
// c.fun(1);//?
// c.fun(2);//?